//
//  HttpConn.m
//  ApiBase
//
//  Created by Liam on 12-10-3.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#import "HttpConn.h"

@interface HttpConn()

- (BOOL)isRunning;
- (void)setRunning:(BOOL)bRunning;

@property (nonatomic, assign) NSInteger statusCode;

@end



@implementation HttpConn

@synthesize statusCode;

- (void)dealloc
{
	SAFE_RELEASE(_error);
	SAFE_RELEASE(_connection);
	SAFE_RELEASE(_outStream);
	SAFE_RELEASE(_request);
	
	[super dealloc];
}
	
- (NSError *)executeRequest:(NSURLRequest *)connectionRequest withOutStream:(NSOutputStream *)outStream connectionDelegate:(id)delegate
{
	@synchronized(self)
	{
		_isRunning = YES;
		_request = [connectionRequest retain];
		_connection = [[NSURLConnection alloc] initWithRequest:connectionRequest delegate:self];
	}
	
	_delegate = delegate;
	
	SAFE_RELEASE(_error);

	if (outStream)
		_outStream = [outStream retain];
	
	if (_connection)
	{
		while ([self isRunning])
		{
			@synchronized(self)
			{
				if (_runLoop == nil)
				{
					_runLoop = [NSRunLoop currentRunLoop];
				}
			}
			[_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
		}
		
		if (self.statusCode != 0
			&& (self.statusCode < 200 || self.statusCode >= 300)) // 错误响应的状态码：400 Bad Request, 500 Internal Server Error
		{
			SAFE_RELEASE(_error);
			//NSLog(@"Status Code: %d", self.statusCode);
			_error = [[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotParseResponse userInfo:nil] retain];
		}
	}
	
	@synchronized(self)
	{
		_runLoop = nil;
	}
	
	SAFE_OPERATION(_connection, cancel);
	
	_delegate = nil;

	return _error;
}
	
- (void)cancel
{
	@synchronized(self)
	{
		_isRunning = NO;
		_isCancel = YES;
		SAFE_OPERATION(_connection, cancel);
		SAFE_RELEASE(_error);
		_error = [[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:nil] retain];
		if (_runLoop)
		{
			CFRunLoopRef rlRef = [_runLoop getCFRunLoop];
			if (rlRef)
			{
				CFRunLoopStop(rlRef);
			}
		}
	}
}

- (BOOL)isRunning
{
	@synchronized(self)
	{
		return _isRunning;
	}
}

- (void)setRunning:(BOOL)bRunning
{
	@synchronized(self)
	{
		_isRunning = bRunning;
	}
}

#pragma mark connection delegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	if (_delegate && [_delegate respondsToSelector:@selector(connection:didReceiveResponse:)])
	{
		[_delegate connection:connection didReceiveResponse:response];
	}
	
	NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response;
	if (resp && [resp isKindOfClass:[NSHTTPURLResponse class]])
	{
		self.statusCode = [resp statusCode];
	}
}

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
{
	if (_delegate && [_delegate respondsToSelector:@selector(connection:willSendRequest:redirectResponse:)])
	{
		[_delegate connection:connection willSendRequest:request redirectResponse:redirectResponse];
	}

	return request;
}

- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
{
	if (_delegate && [_delegate respondsToSelector:@selector(connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)])
	{
		[_delegate connection:connection didSendBodyData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
	}
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	if (_delegate && [_delegate respondsToSelector:@selector(connection:didReceiveData:)])
	{
		[_delegate connection:connection didReceiveData:data];
	} else if (_outStream) {
		[_outStream write:(const uint8_t*)[data bytes] maxLength:[data length]];
	}
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	if (_delegate && [_delegate respondsToSelector:@selector(connectionDidFinishLoading:)])
	{
		[_delegate connectionDidFinishLoading:connection];
	}
	
	[self setRunning:NO];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	if (_delegate && [_delegate respondsToSelector:@selector(connection:didFailWithError:)])
	{
		[_delegate connection:connection didFailWithError:error];
	}
	
	NSLog(@"connection error %@", [error localizedDescription]);
	
	// 错误处理
	SAFE_RELEASE(_error);

	_error = [error retain];
	
	[self setRunning:NO];
}

// For Https

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSLog(@"didReceiveAuthenticationChallenge %@ %zd", [[challenge protectionSpace] authenticationMethod], (ssize_t) [challenge previousFailureCount]);
	
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
	{
        [[challenge sender] useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        [[challenge sender] continueWithoutCredentialForAuthenticationChallenge: challenge];
    }
} 


@end
